package com.phenix.share.superwindow

import android.accessibilityservice.AccessibilityService
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.Gravity
import android.view.MotionEvent
import android.view.SurfaceControl
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewTreeObserver
import android.view.WindowManager
import android.view.accessibility.AccessibilityEvent
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry

fun View.setBorder(
    width: Int = 2,
    color: Int = Color.BLACK,
    cornerRadius: Float = 0f,
    fillColor: Int = Color.TRANSPARENT
) {
    val drawable = GradientDrawable().apply {
        setStroke(width, color)
        setColor(fillColor)
        setCornerRadius(cornerRadius)
    }
    background = drawable
}

@SuppressLint("AccessibilityPolicy")
class SuperFloatingWindowService : AccessibilityService(),
    LifecycleOwner,
    ISuperFloatingWindowCallback {

    private var screenWidth: Int = 0
    private var screenHeight: Int = 0

    private val mLifecycleRegistry = LifecycleRegistry(this)

    private val windowManager: WindowManager by lazy {
        // 获取WindowManager服务
        getSystemService(WINDOW_SERVICE) as WindowManager
    }

    private var mSuperFloatingWindowContentView: View? = null

    private val mHandler = Handler(Looper.getMainLooper())

    private val mTmpRect by lazy { Rect() }


    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "#onCreate...")
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
        with(resources.displayMetrics) {
            screenWidth = widthPixels
            screenHeight = heightPixels
        }
    }

    private fun showSuperFloatingWindow() {
        // 设置LayoutParam
        sSuperFloatingWindowManager.superFloatingWindowCreator?.let { creator ->
            creator.createContentView().let {
                mSuperFloatingWindowContentView = it
                it.visibility = View.GONE
                addOnAttachCallback(it)
                setContentView(it)
                val target = creator.dragTarget(it)
                setDragListener(it, target)
            }
        } ?: Log.e(TAG, "Failed to get superFloatingWindowCreator!")
    }

    private fun gainedFocus(v: View) {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
        (mSuperFloatingWindowContentView?.layoutParams as? WindowManager.LayoutParams)?.let { params ->
            params.flags =
                WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
            windowManager.updateViewLayout(
                mSuperFloatingWindowContentView,
                params
            )
            v.isFocusableInTouchMode = true
            v.isFocusable = true
            v.requestFocus()
            v.setBorder(
                width = 4,
                color = Color.RED,
                cornerRadius = 12f,
                fillColor = Color.LTGRAY
            )
        }
    }

    private fun lossFocus(v: View) {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        (mSuperFloatingWindowContentView?.layoutParams as? WindowManager.LayoutParams)?.let { params ->
            params.flags =
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
            windowManager.updateViewLayout(mSuperFloatingWindowContentView, params)
            v.clearFocus()
            v.isFocusableInTouchMode = false
            v.isFocusable = false
            v.setBorder(
                width = 4,
                color = Color.BLUE,
                cornerRadius = 12f,
                fillColor = Color.LTGRAY
            )
        }
    }

    private fun addOnAttachCallback(view: View) {
        view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {
                handleOnViewAttachedToWindow(v)
            }

            private fun handleOnViewAttachedToWindow(v: View) {
                v.viewTreeObserver.addOnGlobalLayoutListener(object :
                    ViewTreeObserver.OnGlobalLayoutListener {
                    override fun onGlobalLayout() {
                        v.viewTreeObserver.removeOnGlobalLayoutListener(this)
                        v.visibility = View.VISIBLE
                        initOffset()
                    }

                    /**
                     * [优化] 解决Gravity.TOP or Gravity.START 闪一下问题
                     *  通过visibility 解决
                     */
                    fun initOffset() {
                        val params = v.layoutParams as WindowManager.LayoutParams
                        val gt =
                            sSuperFloatingWindowManager.superFloatingWindowCreator?.gravity()
                                ?: (Gravity.TOP or Gravity.START)

                        val horizontalGravity = gt and Gravity.HORIZONTAL_GRAVITY_MASK
                        params.x = when (horizontalGravity) {
                            Gravity.CENTER_HORIZONTAL -> (screenWidth - v.width) / 2
                            Gravity.RIGHT, Gravity.END -> screenWidth - v.width
                            else -> 0
                        }

                        val verticalGravity = gt and Gravity.VERTICAL_GRAVITY_MASK
                        params.y = when (verticalGravity) {
                            Gravity.CENTER_VERTICAL -> (screenHeight - v.height) / 2
                            Gravity.BOTTOM -> screenHeight - v.height
                            else -> 0
                        }
                        windowManager.updateViewLayout(v, params)
                    }
                })
            }

            override fun onViewDetachedFromWindow(v: View) {
                Log.d(TAG, "onViewDetachedFromWindow")
            }

        })
    }

    private fun setDragListener(parent: View, dragView: View?) {
        val params = parent.layoutParams as WindowManager.LayoutParams
        val dragTouchListener = object : OnTouchListener {
            private var startX = 0
            private var startY = 0
            private var touchX = 0f
            private var touchY = 0f

            @SuppressLint("ClickableViewAccessibility")
            override fun onTouch(v: View, event: MotionEvent): Boolean {
                if (sSuperFloatingWindowManager.superFloatingWindowCreator?.isDraggable() == true) {
                    when (event.action) {
                        MotionEvent.ACTION_DOWN -> {
                            startX = params.x
                            startY = params.y
                            touchX = event.rawX // 记录触点X
                            touchY = event.rawY // 记录触点Y
                            return true
                        }

                        MotionEvent.ACTION_MOVE -> {
                            // 计算新位置
                            params.x = startX + (event.rawX - touchX).toInt()
                            params.y = startY + (event.rawY - touchY).toInt()
                            parent.post {
                                windowManager.updateViewLayout(parent, params)
                                sSuperFloatingWindowManager.notifyOnWindowPositionChanged(
                                    params.x,
                                    params.y
                                )
                            }
                            return true
                        }

                        MotionEvent.ACTION_UP -> {
                            if (sSuperFloatingWindowManager.superFloatingWindowCreator?.autoAttachToEdges() == true) {
                                autoAttachToEdge(parent, params) // 触发吸边效果
                            }
                            return true
                        }
                    }
                }
                return false
            }
        }
        parent.setOnTouchListener { v, event ->
            if (event.action == MotionEvent.ACTION_OUTSIDE) {
                // ✅ 点击了 View 外部
                lossFocus(v)
            } else {
                val target = dragView ?: parent
                if (event.action == MotionEvent.ACTION_DOWN) {
                    v.getLocalVisibleRect(mTmpRect)
                    if (mTmpRect.contains(event.x.toInt(), event.y.toInt())) {
                        if (dragTouchListener.onTouch(target, event)) {
                            gainedFocus(v)
                            v.performClick()
                            return@setOnTouchListener true
                        }
                    } else {
                        lossFocus(v)
                    }
                } else if (event.action == MotionEvent.ACTION_MOVE || event.action == MotionEvent.ACTION_UP) {
                    return@setOnTouchListener dragTouchListener.onTouch(target, event)
                }
            }
            return@setOnTouchListener false
        }
    }

    private fun autoAttachToEdge(contentView: View, params: WindowManager.LayoutParams) {
        // TOP | START
        // Other
        val absX = params.x
        val viewCenterX: Int = absX + contentView.width / 2

        // 判断离哪边近
        val targetX = if (viewCenterX < screenWidth / 2) {
            0 // 吸到左边缘
        } else {
            screenWidth - contentView.width // 吸到右边缘
        }
        Log.d(TAG, "#autoAttachToEdge $absX  $targetX $screenWidth $viewCenterX")
        // 添加弹性动画
        val animator = ValueAnimator.ofInt(params.x, targetX)
        animator.addUpdateListener { animation: ValueAnimator? ->
            params.x = animation!!.getAnimatedValue() as Int
            windowManager.updateViewLayout(contentView, params)
        }
        animator.setDuration(ANIM_TIME).start()
    }

    private fun setContentView(view: View) {
        val titleStr = sSuperFloatingWindowManager.superFloatingWindowCreator?.title()
        val w =
            if (sSuperFloatingWindowManager.isMini()) MIN_SIZE_OF_WINDOW else WindowManager.LayoutParams.WRAP_CONTENT
        val h =
            if (sSuperFloatingWindowManager.isMini()) MIN_SIZE_OF_WINDOW else WindowManager.LayoutParams.WRAP_CONTENT
        val layoutParam = WindowManager.LayoutParams().apply {
            title = titleStr
            type = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                //刘海屏延伸到刘海里面
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    layoutInDisplayCutoutMode =
                        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
                }
                WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
            } else {
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            }
            flags =
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
            //将alpha设置为最大遮挡不透明度
            alpha = 0.8f
            width = w
            height = h
            gravity = Gravity.TOP or Gravity.START
            format = PixelFormat.TRANSPARENT
            sSuperFloatingWindowManager.superFloatingWindowCreator
                ?.offsetPoint()
                ?.let { offset ->
                    x = offset.x
                    y = offset.y
                }
        }
        windowManager.addView(view, layoutParam)
    }

    private fun hideSuperFloatingWindow() {
        mSuperFloatingWindowContentView?.let {
            windowManager.removeView(it)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        Log.d(TAG, "#onDestroy...")
        sSuperFloatingWindowManager.removeOnSuperFloatingWindowCallback(this)
    }

    override fun onStartCommand(
        intent: Intent?,
        flags: Int,
        startId: Int
    ): Int {
        Log.d(TAG, "#onStartCommand...")
        return START_STICKY
    }

    override fun onServiceConnected() {
        super.onServiceConnected()
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        val shouldShow =
            sSuperFloatingWindowManager.superFloatingWindowCreator?.showOnConnected() == true
        Log.d(TAG, "#onServiceConnected...shouldShow:$shouldShow")
        sSuperFloatingWindowManager.addOnSuperFloatingWindowCallback(this)
        if (shouldShow) {
            sSuperFloatingWindowManager.show()
        }
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.d(TAG, "#onUnbind...")
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
        sSuperFloatingWindowManager.hide()
        return super.onUnbind(intent)
    }

    override fun onRebind(intent: Intent) {
        super.onRebind(intent)
        Log.d(TAG, "#onRebind...${intent.toUri(0)}")
    }

    override fun onAccessibilityEvent(event: AccessibilityEvent) {
        Log.d(TAG, "#onAccessibilityEvent...$event")
        if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            val cn = "${event.packageName}/${event.className}"
            val state = if (event.isFullScreen) "foreground" else "background"
            Log.d(TAG, "Component $cn is in $state")
        }
    }

    override fun onInterrupt() {
        Log.d(TAG, "#onInterrupt...")
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        Log.d(TAG, "#onConfigurationChanged newConfig:$newConfig")
    }

    override fun attachAccessibilityOverlayToWindow(
        accessibilityWindowId: Int,
        sc: SurfaceControl
    ) {
        super.attachAccessibilityOverlayToWindow(accessibilityWindowId, sc)
        Log.d(
            TAG,
            "#attachAccessibilityOverlayToWindow accessibilityWindowId:$accessibilityWindowId"
        )
    }

    override val lifecycle: Lifecycle
        get() = mLifecycleRegistry

    override fun onVisibilityChanged(isShown: Boolean) {
        mHandler.post {
            Log.d(TAG, "#onVisibilityChanged isShown: $isShown")
            if (isShown) {
                showSuperFloatingWindow()
            } else {
                hideSuperFloatingWindow()
            }
        }
    }

    override fun onWindowSizeChanged(isMini: Boolean) {
        mHandler.post {
            Log.d(TAG, "#onMinimizeChanged isMini: $isMini")
            (mSuperFloatingWindowContentView?.layoutParams as? WindowManager.LayoutParams)?.let {
                if (isMini) {
                    it.width = MIN_SIZE_OF_WINDOW
                    it.height = MIN_SIZE_OF_WINDOW
                } else {
                    it.width = WindowManager.LayoutParams.WRAP_CONTENT
                    it.height = WindowManager.LayoutParams.WRAP_CONTENT
                }
                windowManager.updateViewLayout(mSuperFloatingWindowContentView, it)
            }

        }
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        mHandler.post {
            mSuperFloatingWindowContentView?.let {
                Log.d(TAG, "#onWindowFocusChanged hasFocus: $hasFocus")
                if (hasFocus) {
                    gainedFocus(it)
                } else {
                    lossFocus(it)
                }
            }
        }
    }

    companion object {
        private const val TAG = "SuperFloatingWindowService"
        private const val ANIM_TIME = 300L
        private const val MIN_SIZE_OF_WINDOW = 1

        private val sSuperFloatingWindowManager = SuperFloatingWindowManager.getInstance()
    }
}